import {celebrate, Joi} from "celebrate";
import {withLock} from "easylock";
import * as express from "express";
import {Request} from "express";
import {ConsumeRecordModel} from "../database/models/consumeRecord";
import {GamePrizeModel} from "../database/models/gamePrize";
import {GiftState, MailModel, MailState, MailType} from "../database/models/mail";
import {PlayerModel} from "../database/models/player";
import {ProductModel} from "../database/models/Product";
import {deleteProductStockSafely, PressGroupModel, ProductGroupModel} from "../database/models/ProductGroup";
import {InternalError} from "./error";
import {playerUseCoinOrGemOrPoint} from "./games/lipStickGame";
import {findProductGroupById} from "./helpers/productgroup";
import {Response, withUser} from "./middlewareType"
import {jwtAuthMiddleware} from "./passort";

const router = express.Router()

export const maxAry = (arr, n) => arr.sort((a, b) => b.sortNum - a.sortNum).slice(0, n)

router.get('/group/:category',
  celebrate({
    params: Joi.object({
      category: Joi.string().required().valid(['luckyBox', 'eggDraw'])
    })
  }),
  async (req, res: Response) => {
  try {
    const groups = await ProductGroupModel.find({state: 'on', category: req.params.category})
      .populate('level1')
      .populate('level2')
      .populate('level3')
      .populate('level4')
      .sort({hotNum: 1, createAt: -1})
      .lean()

    const sorted = [].concat(groups)
    const hots = maxAry(groups, 4)
    const final = Array.from(new Set([...hots, ...sorted]))

    res.json({ok: true, data: {groups: final}})
  } catch (e) {
    res.error(e)
  }
})

router.get('/group_detail', async (req, res) => {
  const groups = await ProductGroupModel.find()
    .populate('level1')
    .populate('level2')
    .populate('level3')
    .populate('level4')
    .sort({hotNum: 1, createAt: -1})
    .lean()

  const sorted = [].concat(groups)
  const hots = maxAry(groups, 4)
  const final = Array.from(new Set([...hots, ...sorted]))

  res.json({ok: true, data: {groups: final}})
})

router.get('/pressGroup_detail', async (req, res) => {
  const presses = await PressGroupModel.find()
    .populate('level1')
    .populate('level2')
    .populate('level3')
    .sort({hotNum: 1, createAt: -1})
    .lean()

  const sorted = [].concat(presses)
  const hots = maxAry(presses, 4)
  const final = Array.from(new Set([...hots, ...sorted]))

  if (!final)
    throw  InternalError("NO_SUCH_PRODUCT_GROUP")
  res.json({ok: true, data: {presses: final}})
})

router.get('/groupDetail/:groupId', async (req, res: Response) => {

  try {
    const group = await findProductGroupById(req.params.groupId)
    if (!group)
      throw  InternalError('NO_SUCH_PRODUCT_GROUP')

    res.json({ok: true, data: {group}})

  } catch (err) {
    res.error(err)
  }
})

router.get('/point', async (req, res: Response) => {

  try {
    const points = await ProductModel.find({state: 'on', onPointMarket: true})
      .sort({sortNum: 1, createAt: -1})
      .lean()
    if (!points)
      throw  InternalError("NO_POINT_MARKET_PRODUCT")

    res.json({ok: true, data: {points}})

  } catch (err) {
    res.error(err)
  }
})

router.post('/pointBuy/:productId',
  jwtAuthMiddleware,
  celebrate({params: Joi.object().keys({productId: Joi.string().required()})}),
  async (req: Request & withUser, res: Response) => {
    await withLock(req.user.id, async () => {
      try {
        const product = await ProductModel.findOne({_id: req.params.productId, state: 'on', onPointMarket: true})
        if (!product || product.stock <= 0)
          throw  InternalError("NO_SUCH_PRODUCT")

        const {ok, consume} = await playerUseCoinOrGemOrPoint(req.user, product.pointPrice, product._id, `pointMarket`)
        if (!ok)
          throw InternalError("NO_ENOUGH_POINT")

        const result = await deleteProductStockSafely([product._id])
        if (!result || !result.ok || !result.successList) {
          await ConsumeRecordModel.findByIdAndUpdate(consume, {$set: {success: false}})
          await PlayerModel.findByIdAndUpdate(req.user.id, {$inc: {point: product.pointPrice}})
          await ProductModel.findByIdAndUpdate(product.id, {$set: {state: `off`}})
          throw InternalError("NO_ON_STOCK")
        }

        const prize = await GamePrizeModel.create({
          player: req.user.id,
          product: product.id,
          productName: product.name,
          productModel: product.model,
          productDescription: product.description,
          productUrl: product.coverUrl,
          inviteBy: req.user.inviteBy,
          state: 'idle',
          createAt: new Date(),
          from: 'pointBuy',
          selectState: `notAllowed`
        })
        await MailModel.create({
          title: `积分兑换商品成功`,
          content: `积分商城${prize.productName}兑换成功`,
          to: prize.player,
          type: MailType.NOTICE,
          gift: {prize: prize._id},
          giftState: GiftState.NOTALLOW,
          state: MailState.UNREAD
        })
        res.json({ok: true, data: {prize}})

      } catch (err) {
        res.error(err)
      }
    })
  })

router.get('/:productId', async (req, res: Response) => {
  try {
    const product = await ProductModel.findOne({
      _id: req.params.productId,
    }).select({stock: 0})
      .lean()

    if (!product)
      return res.json({ok: false})

    res.json({ok: true, data: {product}})
  } catch (e) {
    res.error(e)
  }
})

export default router
